package cn.px.service.business;

import cn.hutool.core.collection.CollectionUtil;
import cn.px.activiti.bean.ActObj;
import cn.px.activiti.dao.entity.ActApplyInfo;
import cn.px.activiti.dao.entity.ActAuditRecord;
import cn.px.activiti.service.ActivitiService;
import cn.px.common.constant.CommonConstants;
import cn.px.common.exception.BusinessException;
import cn.px.common.model.UserInfo;
import cn.px.common.util.SecurityUtils;
import cn.px.common.util.StringUtils;
import cn.px.dao.dto.upms.SysDeptDTO;
import cn.px.dao.dto.upms.SysUserDTO;
import cn.px.dao.enums.DeptCodeEnum;
import cn.px.dao.enums.DeptNatureEnum;
import cn.px.dao.mapper.upms.SysDeptMapper;
import cn.px.dao.mapper.upms.SysUserMapper;
import cn.px.dao.vo.SysUserVO;
import cn.px.dao.vo.query.upms.SysDeptVO;
import cn.px.service.upms.SysDeptService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.task.Task;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description 工作流业务
 * @author 品讯科技
 * @date 2024-08
 * @Version Copyright (c) 2019,安徽阡陌网络科技有限公司 All rights reserved.
 */
@AllArgsConstructor
@Service("activitiBusinessService")
@Slf4j
public class ActivitiBusinessService {

    private final ActivitiService activitiService;
    private final SysUserMapper userMapper;
    private final SysDeptMapper deptMapper;
    private final SysDeptService sysDeptService;
    private final TaskService taskService;
    private final RuntimeService runtimeService;
    private final RepositoryService repositoryService;
    ;

    /**
     * 开始流程
     *
     * @param id
     * @param now
     */
    public ActObj startWorkflow(String id, String name, String projectId, String processId, String activitiName, Integer startNode, String roleCode, LocalDateTime now, Integer result) {
        // 重新发起
        UserInfo user = SecurityUtils.getUserInfo();
        ActApplyInfo applyInfo = new ActApplyInfo(id, name, activitiName, startNode, now);
        ActObj obj = new ActObj();
        String userId = getCurrentProjectDeptAudit(projectId, roleCode).getUserId();
        Task task = null;
        if (StringUtils.isNotEmpty(processId)) {
            task = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().singleResult();
            if (task == null) {
                Map<String, Object> map = new HashMap<>(1);
                applyInfo.setUserId(user.getUserId());
                applyInfo.setUserName(user.getRealName());
                map.put("data", applyInfo);
                map.put("userId", applyInfo.getUserId());
                runtimeService.startProcessInstanceById(processId, map);
                task = taskService.createTaskQuery().processInstanceId(id).orderByTaskCreateTime().desc().singleResult();
            }
            Map<String, Object> variables = taskService.getVariables(task.getId());
            List<ActAuditRecord> records = new ArrayList<>();
            Object o = variables.get(CommonConstants.ACT_AUDIT_RECORD);
            if (o != null) {
                records = (List<ActAuditRecord>) o;
            }

            records.add(0, new ActAuditRecord(user.getUserId(), user.getRealName(), "提交申请",
                    now, true, task.getId(), startNode));
            Map<String, Object> map = new HashMap<>();
            map.put(CommonConstants.ACT_AUDIT_RECORD, records);
            taskService.complete(task.getId(), map);
            task = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().singleResult();
            taskService.setAssignee(task.getId(), userId);
        } else {
//            ActApplyInfo applyInfo = new ActApplyInfo(id, name, activitiName, startNode, now);
            processId = activitiService.startProcess(activitiName, applyInfo, getCurrentProjectDeptAudit(projectId, roleCode).getUserId(), result);
            task = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().singleResult();
        }
        obj.setTaskId(task.getId());
        obj.setAssignee(userId);
        obj.setProcessId(processId);
        return obj;
    }

    /**
     * 开始流程
     *
     * @param id
     * @param now
     */
    public ActObj startWorkflow(String id, String name, String projectId, String processId, String activitiName, Integer startNode, String roleCode, LocalDateTime now, Integer result, String applyComment) {
        // 重新发起
        UserInfo user = SecurityUtils.getUserInfo();
        ActApplyInfo applyInfo = new ActApplyInfo(id, name, activitiName, startNode, now);
        ActObj obj = new ActObj();
        String userId = getCurrentProjectDeptAudit(projectId, roleCode).getUserId();
        Task task = null;
        if (StringUtils.isNotEmpty(processId)) {
            task = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().singleResult();
            if (task == null) {
                Map<String, Object> map = new HashMap<>(1);
                applyInfo.setUserId(user.getUserId());
                applyInfo.setUserName(user.getRealName());
                map.put("data", applyInfo);
                map.put("userId", applyInfo.getUserId());
                runtimeService.startProcessInstanceById(processId, map);
                task = taskService.createTaskQuery().processInstanceId(id).orderByTaskCreateTime().desc().singleResult();
            }
            Map<String, Object> variables = taskService.getVariables(task.getId());
            List<ActAuditRecord> records = new ArrayList<>();
            Object o = variables.get(CommonConstants.ACT_AUDIT_RECORD);
            if (o != null) {
                records = (List<ActAuditRecord>) o;
            }

            records.add(0, new ActAuditRecord(user.getUserId(), user.getRealName(), applyComment,
                    now, true, task.getId(), startNode));
            Map<String, Object> map = new HashMap<>();
            map.put(CommonConstants.ACT_AUDIT_RECORD, records);
            map.put("result", result);
            taskService.complete(task.getId(), map);
            task = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().singleResult();
            taskService.setAssignee(task.getId(), userId);
        } else {
//            ActApplyInfo applyInfo = new ActApplyInfo(id, name, activitiName, startNode, now);
            processId = activitiService.startProcess(activitiName, applyInfo, getCurrentProjectDeptAudit(projectId, roleCode).getUserId(), result, applyComment);
            task = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().singleResult();
        }
        obj.setTaskId(task.getId());
        obj.setAssignee(userId);
        obj.setProcessId(processId);
        return obj;
    }

    /**
     * 执行流程
     *
     * @param taskId
     * @param processId
     * @param projectId
     * @param result
     * @param desc
     * @param auditFlag
     * @param node
     * @param roleCode
     * @param rank
     * @param now
     */
    public ActObj executeFlow(String taskId, String processId, String projectId, Integer result, String desc, Boolean auditFlag,
                              Integer node, String roleCode, String rank, LocalDateTime now) {
        log.info(String.format("taskId:%s  processId:%s projectId:%s rank:%s roleCode:%s ", taskId, processId, projectId, rank, roleCode));
        // 执行审批流程
        ActObj obj = new ActObj();
        UserInfo user = SecurityUtils.getUserInfo();
        Map<String, Object> variables = taskService.getVariables(taskId);
        List<ActAuditRecord> records = new ArrayList<>();
        Object o = variables.get(CommonConstants.ACT_AUDIT_RECORD);
        if (o != null) {
            records = (List<ActAuditRecord>) o;
        }
        records.add(0, new ActAuditRecord(user.getUserId(), user.getRealName(), desc,
                now, auditFlag, taskId, node));
        Map<String, Object> map = new HashMap<>();
        map.put("result", result);
        map.put(CommonConstants.ACT_AUDIT_RECORD, records);
        taskService.complete(taskId, map);
        if (result > 1) {

            String userId = getLeadDeptAuditUserId(projectId, rank, roleCode).getUserId();
            log.info(String.format("userId:%s  projectId:%s rank:%s roleCode:%s ", userId, projectId, rank, roleCode));
            Task task = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().singleResult();
            taskService.setAssignee(task.getId(), userId);
            obj.setAssignee(userId);
            obj.setTaskId(task.getId());
        }
        return obj;

    }

    /**
     * 执行流程
     *
     * @param taskId
     * @param processId
     * @param projectId
     * @param result
     * @param desc
     * @param auditFlag
     * @param node
     * @param now
     */
    public ActObj executeFlow(String taskId, String processId, String projectId, Integer result, String desc, Boolean auditFlag,
                              Integer node, LocalDateTime now) {
        // 执行审批流程
        UserInfo user = SecurityUtils.getUserInfo();
        ActObj obj = new ActObj();
        Map<String, Object> variables = taskService.getVariables(taskId);
        List<ActAuditRecord> records = new ArrayList<>();
        Object o = variables.get(CommonConstants.ACT_AUDIT_RECORD);
        if (o != null) {
            records = (List<ActAuditRecord>) o;
        }
        records.add(0, new ActAuditRecord(user.getUserId(), user.getRealName(), desc,
                now, auditFlag, taskId, node));
        Map<String, Object> map = new HashMap<>();
        map.put("result", result);
        map.put(CommonConstants.ACT_AUDIT_RECORD, records);
        taskService.complete(taskId, map);
        if (result > 1) {
            Task task = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().singleResult();
            String activitiId = getCurrentFlowId(processId);
            String[] data = activitiId.split("\\.");
            String userId = getLeadDeptAuditUserId(projectId, data[0], data[1]).getUserId();
            taskService.setAssignee(task.getId(), userId);
            obj.setAssignee(userId);
            obj.setTaskId(task.getId());
        }
        return obj;

    }

    /**
     * 获取当前节点ID
     *
     * @param processId
     * @return
     */
    public String getCurrentFlowId(String processId) {
        ExecutionEntity execution = (ExecutionEntity) runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        //当前流程节点Id信息
        return execution.getActivityId();
    }

    /**
     * 当前部门采购计划审批负责人
     *
     * @return
     */
    public SysUserVO getCurrentProjectDeptAudit(String projectId, String roleCode) {
        SysUserDTO query = new SysUserDTO();
       /* if (StringUtils.isNotEmpty(projectId)) {
            SysDept dept = deptMapper.selectByPrimaryKey(projectId);
            Weekend<SysDept> weekend = new Weekend<>(SysDept.class);
            WeekendCriteria<SysDept, Object> weekendCriteria = weekend.weekendCriteria();
            weekendCriteria.andLike(SysDept::getDeptCode, dept.getDeptCode() + "%");
            List<SysDept> depts = deptMapper.selectByExample(weekend);
            query.setDeptIds(depts.stream().map(item -> item.getDeptId()).collect(Collectors.toList()));
        }*/
        query.setRoleCode(roleCode);
        List<SysUserVO> users = userMapper.selectDeptRoleUser(query);
        if (CollectionUtil.isNotEmpty(users)) {
            return users.get(0);
        }
        throw new BusinessException("部门审批人没有指定");
    }

    /**
     * 当前部门某角色的人
     *
     * @return
     */
    public List<SysUserVO> getCurrentProjectDeptUserByRole(String projectId, String roleCode) {
        SysUserDTO query = new SysUserDTO();
       /* if (StringUtils.isNotEmpty(projectId)) {
            SysDept dept = deptMapper.selectByPrimaryKey(projectId);
            Weekend<SysDept> weekend = new Weekend<>(SysDept.class);
            WeekendCriteria<SysDept, Object> weekendCriteria = weekend.weekendCriteria();
            weekendCriteria.andLike(SysDept::getDeptCode, dept.getDeptCode() + "%");
            List<SysDept> depts = deptMapper.selectByExample(weekend);
            query.setDeptIds(depts.stream().map(item -> item.getDeptId()).collect(Collectors.toList()));
        }*/
        query.setRoleCode(roleCode);
        List<SysUserVO> users = userMapper.selectDeptRoleUser(query);
        if (CollectionUtil.isNotEmpty(users)) {
            return users;
        }
        return new ArrayList<>();
    }

    /**
     * 上级部门审批负责人
     *
     * @return
     */
    public SysUserVO getLeadDeptAuditUserId(String projectId, String rank, String roleCode) {
        SysUserDTO query = new SysUserDTO();
        /*if (StringUtils.isNotEmpty(projectId)) {
            SysDept dept = deptMapper.selectByPrimaryKey(projectId);
            Weekend<SysDept> weekend = new Weekend<>(SysDept.class);
            WeekendCriteria<SysDept, Object> weekendCriteria = weekend.weekendCriteria();
            weekendCriteria.andIn(SysDept::getDeptCode, splitCodes(dept.getDeptCode()));
            weekendCriteria.andEqualTo(SysDept::getNature, rank);
            List<SysDept> depts = deptMapper.selectByExample(weekend);
            List<String> deptIds = depts.stream().map(item -> item.getDeptId()).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(deptIds)) {
                throw new BusinessException("上级部门不存在");
            }
            List<SysDeptVO> deptVOs = sysDeptService.allChildList(new SysDeptDTO().setAncestorList(deptIds));
            deptIds = deptVOs.stream().map(item -> item.getDeptId()).collect(Collectors.toList());
            query.setDeptIds(deptIds);
        }*/
        query.setRoleCode(roleCode);
        List<SysUserVO> users = userMapper.selectDeptRoleUser(query);
        if (CollectionUtil.isNotEmpty(users)) {
            return users.get(0);
        }
        throw new BusinessException("部门审批人没有指定");
    }

    /**
     * 上级部门审批负责人
     *
     * @return
     */
    public List<SysUserVO> getLeadDeptUserByRole(String projectId, String rank, String roleCode) {
        SysUserDTO query = new SysUserDTO();
        /*if (StringUtils.isNotEmpty(projectId)) {
            SysDept dept = deptMapper.selectByPrimaryKey(projectId);
            Weekend<SysDept> weekend = new Weekend<>(SysDept.class);
            WeekendCriteria<SysDept, Object> weekendCriteria = weekend.weekendCriteria();
            weekendCriteria.andIn(SysDept::getDeptCode, splitCodes(dept.getDeptCode()));
            weekendCriteria.andEqualTo(SysDept::getNature, rank);
            List<SysDept> depts = deptMapper.selectByExample(weekend);
            List<String> deptIds = depts.stream().map(item -> item.getDeptId()).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(deptIds)) {
                throw new BusinessException("上级部门不存在");
            }
            List<SysDeptVO> deptVOs = sysDeptService.allChildList(new SysDeptDTO().setAncestorList(deptIds));
            deptIds = deptVOs.stream().map(item -> item.getDeptId()).collect(Collectors.toList());
            query.setDeptIds(deptIds);
        }*/
        query.setRoleCode(roleCode);
        List<SysUserVO> users = userMapper.selectDeptRoleUser(query);
        if (CollectionUtil.isNotEmpty(users)) {
            return users;
        }
        return new ArrayList<>();
    }

    /**
     * 获取当前审批用户
     *
     * @param processId
     * @return
     */
    public String getCurrentAuditUserName(String processId) {
        if (StringUtils.isEmpty(processId)) {
            return null;
        }
        Task task = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().singleResult();
        if (task != null && StringUtils.isNotEmpty(task.getAssignee())) {
            return userMapper.selectByPrimaryKey(task.getAssignee()).getRealName();
        }
        return null;
    }

    /**
     * 拆分
     *
     * @param deptCode
     * @return
     */
    private List<String> splitCodes(String deptCode) {
        List<String> result = new ArrayList<>();
        int length = deptCode.length();
        int index = length / 3;
        for (int i = 0; i < index; i++) {
            int j = i * 3;
            result.add(deptCode.substring(0, j + 3));
        }
        result.add("001");
        return result;
    }

    /**
     * 获取区域总部
     *
     * @param projectId
     * @return
     */
    public SysDeptVO getRegionDept(String projectId) {
        SysDeptDTO sysDeptDTO = new SysDeptDTO();
        sysDeptDTO.setDescendant(projectId);
        sysDeptDTO.setNature(DeptNatureEnum.JITUAN.getValue());
        sysDeptDTO.setName("区域");
        List<SysDeptVO> list = sysDeptService.allParentList(sysDeptDTO);
        if (CollectionUtil.isNotEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    /**
     * 分公司审批负责人
     *
     * @param companyId 分公司id
     * @param rank 部门标识
     * @param roleCode 角色代码
     * @return
     */
    public SysUserVO getLeadDeptAuditUserIdInCompany(String companyId, String rank, String roleCode) {
        SysUserDTO query = new SysUserDTO();
        /*if (StringUtils.isNotEmpty(companyId)) {
            SysDept dept = deptMapper.selectByPrimaryKey(companyId);
            Weekend<SysDept> weekend = new Weekend<>(SysDept.class);
            WeekendCriteria<SysDept, Object> weekendCriteria = weekend.weekendCriteria();
            weekendCriteria.andIn(SysDept::getDeptCode, splitCodes(dept.getDeptCode()));
            weekendCriteria.andEqualTo(SysDept::getNature, rank);
            List<SysDept> depts = deptMapper.selectByExample(weekend);
            List<String> deptIds = depts.stream().map(item -> item.getDeptId()).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(deptIds)) {
                throw new BusinessException("上级部门不存在:" + dept.getName());
            }
            List<SysDeptVO> deptVOs = sysDeptService.allChildList(new SysDeptDTO().setAncestorList(deptIds));
            deptIds = deptVOs.stream().map(item -> item.getDeptId()).collect(Collectors.toList());
            query.setDeptIds(deptIds);
        }*/
        query.setRoleCode(roleCode);
        List<SysUserVO> users = userMapper.selectDeptRoleUser(query);
        if (CollectionUtil.isNotEmpty(users)) {
            return users.get(0);
        }
        throw new BusinessException("部门审批人或者某角色人员没有指定：" + roleCode);
    }

    /**
     * 获取二级项目
     *
     * @param projectId
     * @return
     */
    public SysDeptVO getViceDept(String projectId) {
        SysDeptDTO sysDeptDTO = new SysDeptDTO();
        sysDeptDTO.setDescendant(projectId);
        sysDeptDTO.setCode(DeptCodeEnum.ER_JI_XIANG_MU_BU.getValue());
        List<SysDeptVO> list = sysDeptService.allParentList(sysDeptDTO);
        if (CollectionUtil.isNotEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    /**
     * 获取集团
     *
     * @param projectId
     * @return
     */
    public SysDeptVO getGroupDept(String projectId) {
        SysDeptDTO sysDeptDTO = new SysDeptDTO();
        sysDeptDTO.setDescendant(projectId);
        sysDeptDTO.setNature(DeptNatureEnum.JITUAN.getValue());
        List<SysDeptVO> list = sysDeptService.allParentList(sysDeptDTO);
        if (CollectionUtil.isNotEmpty(list)) {
            for (int i = list.size() - 1; i >= 0; i--) {
                SysDeptVO item = list.get(i);
                if (!item.getName().contains("区域")) {
                    return item;
                }
            }
        }
        return null;
    }
}
